#include<iostream>
#include<algorithm>
using namespace std;

int n, m=0;
int b[350000] = {0};

struct node
{
    int time, ddl;
}a[350000];

bool cmp(node a, node b) {
    if (a.ddl != b.ddl)
        return a.ddl < b.ddl;
    return a.time < b.time;
}

int main() {
    cin >> n;
    for (int i=0; i<n; i++)
        cin >> a[i].time >> a[i].ddl;

    sort(a, a+n, cmp);

    for (int i=0; i<n; i++) {
        // i 表示第几个事件
        for (int j=m; j>=0; j--) {
            // j 表示已有并填装到b数组的事件
            int t = b[j] + a[i].time;
            if(b[j+1]!=0 && t>=b[j+1])
            // 这里用break的原因是因为当出现这类情况时候，数组前面数据已为最优解，
            // 因此无需维护，所以这里需要用到break语句。
                break;
            if (t <= a[i].ddl) {
                b[j+1] = t;
                if(j == m)
                    m++;
            }
        }
    }

    for (int i=0; i<=m; i++) {
        printf("%5d", b[i]);
    }
    return 0;
}